;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; side effect mapper functionality
;; this is where the magic happens:
;; side effects are created from p systems - producing something 'tangible' from p system definitions
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; NOTE:
;; putting this in another namespace causes issues with macros
;; for example, the instantiation of the window takes place in a
;; separate namespace from the default 'user' namespace
;; so when trying to refer to it outside of the user namespace
;; (e.g. this one) from other macros or functions results in an error:
;; java.lang.Exception: Can't refer to qualified var that doesn't exist (NO_SOURCE_FILE:12)

(use 'psystem.psys)
(load-file "object-mappings.clj")

(import myturtle.Turtle)


(defn object-mapper
  "Map an object to a side effect."
  [o mp]
  (get mp (:value o) (get mp 'default)))


(defn membrane-mapper
  "Map a membrane to side effects.
   Takes the membrane id as a mapper to a set of object side effect mappers."
  [mem mem-map]
  (let [sub-ls (if (empty? (:memz mem))
		 []
		 (reduce
		  conj
		  []
		  (reduce conj
			  (map (fn [x] (membrane-mapper x mem-map)) (:memz mem)))))
	oz (:objz mem)
	mp (get mem-map (:id mem))]
    ;; apply object mapper to each object in this membrane
    (reduce conj sub-ls (map (fn [x] (object-mapper x mp)) oz))))


(defn apply-membrane-mapper
  "Apply membrane map to multiple membranes."
  [mz mem-map]
  (apply concat (map (fn [x] (membrane-mapper x mem-map)) mz)))


;; (defn se-mapper
;;   "Side effect mapper."
;;   [psys mem-map]
;;   (->
;;    [(init-turtle)
;;     ;; apply membrane mapper to each membrane in this p system
;;     (map eval
;; 	 (apply-membrane-mapper (:membranez psys) mem-map))
;;     (post-turtle)]))


(defn value-mapper
  "Apply value map to values."
  [vals value-map]
  (map #(get value-map %) vals))
